package com.xxxtea.component;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.xxxtea.common.MerchantContext;
import com.xxxtea.common.UserContext;
import com.xxxtea.common.anno.AutowiredUserId;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Date;

import static com.xxxtea.common.Constants.*;

/**
 * 自定义元数据对象处理器
 * 
 * 实现MyBatis-Plus的自动填充功能，在插入和更新操作时自动设置：
 * - 用户ID、创建人、更新人
 * - 商家ID（多租户支持）
 * - 创建时间、更新时间
 * - 支持@AutowiredUserId注解的字段自动注入
 * 
 * @author badman
 * @since 1.0.0
 */
@Slf4j
@Component
public class CustomMetaObjectHandler implements MetaObjectHandler {

	/**
	 * 插入操作时的自动填充
	 * 若有值则不覆盖，保持原有值
	 * 
	 * @param metaObject 元数据对象
	 */
	@Override
	public void insertFill(MetaObject metaObject) {
		// 如果用户已登录，填充用户相关字段
		if (UserContext.isLogin()) {
			// 处理@AutowiredUserId注解的字段
			this.autowiredUserId(metaObject);
			// 填充用户ID
			this.strictInsertFill(metaObject, USER_ID_FIELD, Integer.class, UserContext.getId());
			// 填充创建人和更新人
			this.strictInsertFill(metaObject, CREATE_BY_FIELD, String.class, UserContext.getUser().getNickname());
			this.strictInsertFill(metaObject, UPDATE_BY_FIELD, String.class, UserContext.getUser().getNickname());
		}

		// 如果商家上下文存在，填充商家ID
		if (MerchantContext.getMerchant() != null) {
			this.strictInsertFill(metaObject, "merchantId", Integer.class, MerchantContext.getId());
		}
		// 填充创建时间和更新时间
		this.strictInsertFill(metaObject, CREATE_TIME_FIELD, Date.class, new Date());
		this.strictInsertFill(metaObject, UPDATE_TIME_FIELD, Date.class, new Date());
	}

	/**
	 * 更新操作时的自动填充
	 * 
	 * @param metaObject 元数据对象
	 */
	@Override
	public void updateFill(MetaObject metaObject) {
		// 如果用户已登录，填充更新人
		if (UserContext.isLogin()) {
			this.strictUpdateFill(metaObject, UPDATE_BY_FIELD, String.class, UserContext.getUser().getNickname());
		}
		// 填充更新时间
		this.strictUpdateFill(metaObject, UPDATE_TIME_FIELD, Date.class, new Date());
	}

	/**
	 * 处理@AutowiredUserId注解的字段
	 * 自动注入当前用户ID到标记的字段中
	 * 
	 * @param metaObject 元数据对象
	 */
	private void autowiredUserId(MetaObject metaObject) {
		Class<?> clazz = metaObject.getOriginalObject().getClass();
		// 遍历实体类的所有字段
		for (Field field : clazz.getDeclaredFields()) {
			// 检查是否有@AutowiredUserId注解
			AutowiredUserId annotation = field.getAnnotation(AutowiredUserId.class);
			if (annotation == null) {
				continue;
			}
			try {
				// 设置字段值为当前用户ID
				this.setFieldValByName(field.getName(), UserContext.getId(), metaObject);
				log.info("成功注入userId! entity: {}, field: {}, value: {}", clazz.getSimpleName(), field.getName(), UserContext.getId());
			} catch (Exception e) {
				throw new RuntimeException("@AutowiredUserId标记的字段和userId类型不符");
			}
		}
	}

}